package com.unbiz.common;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.unbiz.common.convert.ObjectConverter;

public class MapUtil {

	/**
	 * asMap("k1",1,"k2",2)
	 * 
	 * @param params
	 * @return
	 */
	public static Map asMap(Object... keyValues) {
		Map result = new LinkedHashMap(keyValues.length+5);
		for(int i = 0; i < keyValues.length; i+=2) {
			Object key = keyValues[i];
			Object value = keyValues[i+1];
			result.put(key, value);
		}
		return result;
	}

	/**
	 * asMap(new User())
	 * 
	 * @param params
	 * @return
	 */
	public static Map<String, Object> asMap(Object obj) {
		if (obj == null)
			return null;
		try {

			Map<String, Object> map = new HashMap<String, Object>();

			BeanInfo beanInfo;

			beanInfo = Introspector.getBeanInfo(obj.getClass());

			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor property : propertyDescriptors) {
				String key = property.getName();
				if (key.compareToIgnoreCase("class") == 0) {
					continue;
				}
				Method getter = property.getReadMethod();
				Object value = getter != null ? getter.invoke(obj) : null;
				map.put(key, value);
			}
			return map;
		} catch (IntrospectionException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;
	}

	// string as number
	public static Comparator<Object> stringComparator = new Comparator<Object>() {
		public int compare(Object entry1, Object entry2) {
			int value1 = 0, value2 = 0;
			try {
				value1 = getInt(entry1.toString());
				value2 = getInt(entry2.toString());
			} catch (NumberFormatException e) {
				value1 = 0;
				value2 = 0;
			}
			return value2 - value1;
		}

		private int getInt(String str) {
			int i = 0;
			try {
				Pattern p = Pattern.compile("^\\d+");
				Matcher m = p.matcher(str);
				if (m.find()) {
					i = Integer.valueOf(m.group());
				}
			} catch (NumberFormatException e) {
				e.printStackTrace();
			}
			return i;
		}
	};

	// value support Comparable
	public static  Comparator<Comparable> defaultValueComparator = new Comparator<Comparable>() {

		public int compare(Comparable value1, Comparable value2) {			
			try {			
				int ret = value1.compareTo(value2);
				return ret;
			} catch (Exception e) {
				throw e;
			}
		}
	};

	static class DefaultEntryComparator<K, V> implements Comparator<Map.Entry<K, V>> {
		private Comparator<V> valueComparator;
		private boolean isReverse = false;

		public DefaultEntryComparator(Comparator<V> valueComparator) {
			this.valueComparator = valueComparator;
		}

		public DefaultEntryComparator(Comparator<V> valueComparator, boolean isReverse) {
			this.valueComparator = valueComparator;
			this.isReverse = isReverse;
		}

		public int compare(Map.Entry<K, V> entry1, Map.Entry<K, V> entry2) {
			V value1, value2;
			try {
				value1 = (entry1.getValue());
				value2 = (entry2.getValue());
				if (isReverse) {
					return valueComparator.compare(value2, value1);
				}
				return valueComparator.compare(value1, value2);

			} catch (Exception e) {
				throw e;
			}
		}
	};

	// value support Comparable
	public static DefaultEntryComparator defaultComparator = new DefaultEntryComparator(defaultValueComparator);
	public static DefaultEntryComparator defaultReverseComparator = new DefaultEntryComparator(defaultValueComparator,true);

	//
	public static <K, V> LinkedHashMap<K, V> sortMapByValue(Map<K, V> oriMap, Comparator<V> valueComparator) {
		LinkedHashMap<K, V> sortedMap = new LinkedHashMap<K, V>();
		if (oriMap != null && !oriMap.isEmpty()) {
			List<Map.Entry<K, V>> entryList = new ArrayList<Map.Entry<K, V>>(oriMap.entrySet());

			Collections.sort(entryList, new DefaultEntryComparator(valueComparator));

			Iterator<Map.Entry<K, V>> iter = entryList.iterator();
			Map.Entry<K, V> tmpEntry = null;
			while (iter.hasNext()) {
				tmpEntry = iter.next();
				sortedMap.put(tmpEntry.getKey(), tmpEntry.getValue());
			}
		}
		return sortedMap;
	}

	// sort by value Comparable methode
	// reverse
	public static <K, V> LinkedHashMap<K, V> sortMapByValue(Map<K, V> oriMap, boolean reverse) {
		LinkedHashMap<K, V> sortedMap = new LinkedHashMap<K, V>();
		if (oriMap != null && !oriMap.isEmpty()) {
			List<Map.Entry<K, V>> entryList = new ArrayList<Map.Entry<K, V>>(oriMap.entrySet());
			if (reverse) {
				Collections.sort(entryList, defaultReverseComparator);
			} else {
				Collections.sort(entryList, defaultComparator);
			}

			Iterator<Map.Entry<K, V>> iter = entryList.iterator();
			Map.Entry<K, V> tmpEntry = null;
			while (iter.hasNext()) {
				tmpEntry = iter.next();
				sortedMap.put(tmpEntry.getKey(), tmpEntry.getValue());
			}
		}
		return sortedMap;
	}

	/**
	 * 使用 Map按key进行排序
	 * 
	 * @param map
	 * @return
	 */
	public static <K, V> SortedMap<K, V> sortMapByKey(Map<K, V> map, Comparator<K> comparator) {
		SortedMap<K, V> sortMap = new TreeMap<K, V>(comparator);
		sortMap.putAll(map);
		return sortMap;
	}

	public static <K, V> boolean save(Map<K, V> dfMap, String filePath) {
		StringBuffer buffer = new StringBuffer();
		try {
			FileWriter writer = new FileWriter(filePath, false);
			Set<Map.Entry<K, V>> sets = dfMap.entrySet();
			for (Map.Entry<K, V> entry : sets) {
				K key = entry.getKey();
				V value = entry.getValue();				
				buffer.append(key);
				buffer.append(":");
				buffer.append(value).append("\n");
				writer.append(buffer);
				buffer.setLength(0);
			}
			
			writer.close();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public static <K, V> boolean load(Map<String, V> dfMap, Class<V> clazz, String filePath){
		return load(dfMap,clazz,filePath,':');
	}

	public static <K, V> boolean load(Map<String, V> dfMap, Class<V> clazz, String filePath,char sep) {

		BufferedReader reader = null;
		try {
			File file = new File(filePath);
			reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));

			String tempString = null;
			int line = 1;
			// 一次读入一行，直到读入null为文件结束
			while ((tempString = reader.readLine()) != null) {
				// 显示行号
				// System.out.println("line " + line + ": " + tempString);
				if (!tempString.startsWith("#")) {
					int kPos = tempString.indexOf(sep);
					String key = null;					
					if(kPos>0){
						key = tempString.substring(0,kPos);
						String strArray = tempString.substring(kPos+1).trim();
						if (strArray.length() > 0) {
							Object value = objectConverter.toConvert(strArray, clazz);
							if (value != null) {
								dfMap.put(key,(V)value);
							}
						}
					}
					
				}
				line++;
			}

		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}

		return true;
	}

	protected static ObjectConverter<?> objectConverter = ObjectConverter.getInstance();

}
